/*
	File:				Game.cpp
	Course:		SGP 1208
	Author:		Kori Po
	Purpose:	Contain / manage the game code
						Manage all of the SGD Wrappers
						Game State Machine
*/

#include "Game.h"
#include "MainMenuState.h"
#include "GameplayState.h"

/*static*/ CGame* CGame::GetInstance( void )
{
	// Static local variable - stored in GLOBAL memory
	// - created the FIRST time the function is called
	// - destroyed at the END of the APPLICATION
	static CGame s_Instance;

	return &s_Instance;
}


CGame::CGame(void)
{
	// Assign the data members to 'clean' values
	m_nScreenWidth	= 1;
	m_nScreenHeight	= 1;
	m_bIsWindowed	= true;

	m_pD3D			= nullptr;
	m_pDI			= nullptr;
	m_pTM			= nullptr;
	m_pXA			= nullptr;

	m_pCurrState	= nullptr;

	m_dwCurrTime	= 0;
}


CGame::~CGame(void)
{
}


// 3 Actions for any game: Setup, Play, Cleanup
void CGame::Initialize( HWND hWnd, HINSTANCE hInstance,
					int nScreenWidth, int nScreenHeight,
					bool bIsWindowed )
{
	// Store the parameters
	m_nScreenWidth		= nScreenWidth;
	m_nScreenHeight		= nScreenHeight;
	m_bIsWindowed		= bIsWindowed;


	// Access the SGD Wrappers
	m_pD3D				= CSGD_Direct3D::GetInstance();
	m_pDI				= CSGD_DirectInput::GetInstance();
	m_pTM				= CSGD_TextureManager::GetInstance();
	m_pXA				= CSGD_XAudio2::GetInstance();

	
	// Initialize the wrappers
	m_pD3D->InitDirect3D( hWnd, nScreenWidth, nScreenHeight, bIsWindowed, true );
	m_pDI->InitDirectInput( hWnd, hInstance, DI_KEYBOARD | DI_MOUSE | DI_JOYSTICKS, DI_MOUSE );
	m_pTM->InitTextureManager( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->InitXAudio2();

	// Set the starting state
	ChangeState( CMainMenuState::GetInstance() );


	// Store the current time
	m_dwCurrTime = GetTickCount();
}

bool CGame::Main( void )
{
	// Exit if there is no state
	if( m_pCurrState == nullptr )
		return false;


	// Check input
	if( Input() == false )
		return false;


	
	// Exit if there is no state
	if( m_pCurrState == nullptr )
		return false;


	// Update
	Update();
	
	
	// Exit if there is no state
	if( m_pCurrState == nullptr )
		return false;
	
	// Render
	Render();

	
	// Exit if there is no state
	if( m_pCurrState == nullptr )
		return false;


	// Keep playing
	return true;
}

void CGame::Shutdown( void )
{
	// Exit the current state
	ChangeState( nullptr );

	// Shutdown the SGD Wrappers (in reverse order)
	if( m_pXA != nullptr )
	{
		m_pXA->ShutdownXAudio2();
		m_pXA = nullptr;
	}
	if( m_pTM != nullptr )
	{
		m_pTM->ShutdownTextureManager();
		m_pTM = nullptr;
	}
	if( m_pDI != nullptr )
	{
		m_pDI->ShutdownDirectInput();
		m_pDI = nullptr;
	}
	if( m_pD3D != nullptr )
	{
		m_pD3D->ShutdownDirect3D();
		m_pD3D = nullptr;
	}

}	

bool CGame::Input( void )
{
	// Refresh the input
	m_pDI->ReadDevices();

	// Allow the current state to handle input
	return m_pCurrState->Input();
}

void CGame::Update( void )
{
	// Refresh the audio
	m_pXA->Update();


	// Calculate the elapsed time since the last call to Update
	DWORD dwNow = GetTickCount();
	float fElapsedTime = (dwNow - m_dwCurrTime) * 0.001f;
	m_dwCurrTime = dwNow;


	// Allow the current state to update
	m_pCurrState->Update( fElapsedTime );
}

void CGame::Render( void )
{
	// Clear the background
	m_pD3D->Clear( 255, 0, 255 );

	// Start D3D rendering
	m_pD3D->DeviceBegin();
	m_pD3D->SpriteBegin();


	// Allow the current state to render
	m_pCurrState->Render();

	// End D3D rendering (draw to buffer)
	m_pD3D->SpriteEnd();
	m_pD3D->DeviceEnd();

	// Render the buffer to the screen
	m_pD3D->Present();
}

// State Machine:
void CGame::ChangeState( IState* pNewState )
{
	// Unload the existing state (if any)
	if( m_pCurrState != nullptr )
		m_pCurrState->Exit();


	m_pCurrState = pNewState;


	// Load the new state (if any)
	if( m_pCurrState != nullptr )
		m_pCurrState->Enter();
}
